#include "carplayExt.h"
#include "AppleCarPlay_AppStub.h"
#include "CarPlayProtocol.h"
#include <unordered_map>
#include <sys/system_properties.h>

static ICarplayCallbacks* g_callbacks = nullptr;
std::unordered_map<std::string, std::string> mapTypeString;
std::unordered_map<std::string, int> mapTypeInt;

static CarPlayProtocolDelegate	c2iDelegate;

static int	gPlaybackStatus = 0;

//the following is export by protocol
void iap2LinkStatusExt(int status) {
	if (g_callbacks) {
		g_callbacks->iap2LinkStatus(status);
	}
}

int iap2WriteDataExt(char *buf, int len) {
	if (g_callbacks) {
		return g_callbacks->iap2WriteData(buf, len);
	}
	return 0;
}

void carplaySessionStartExt() {
	if (g_callbacks) {
		g_callbacks->carplaySessionStart();
	}
}

void carplaySessionStopExt() {
	if (g_callbacks) {
		g_callbacks->carplaySessionStop();
	}
}

int switchUsbModeCBExt(DongleUsbMode mode) {
	UsbMode m = (UsbMode)mode;
	if (g_callbacks) {
		return g_callbacks->switchUsbModeCB(m);
	}
	return 0;
}

void appleTimeUpdateCBExt(long long time) {
	if (g_callbacks) {
		g_callbacks->appleTimeUpdateCB(time);
	}

}

void appleLanguageUpdateCBExt(const char *lang) {
	if (g_callbacks) {
		g_callbacks->appleLanguageUpdateCB(lang);
	}
}

void appleCallStateUpdateCBExt(const char *remoteId, const char *displayName,
		int status, int direction, const char *uuid, const char *addrBookId,
		const char *label, int service) {

	if (g_callbacks) {
		g_callbacks->appleCallStateUpdateCB(remoteId, displayName, status,
				direction, uuid, addrBookId, label, service);
	}
}

void appleNowPlayingUpdateCBExt(const char *mediaItemTitle,
										const char *mediaItemAlbumTitle,
										const char *mediaItemArtist,
										int mediaDuration,int state) {

	gPlaybackStatus = state;
	if (g_callbacks) {
		g_callbacks->appleNowPlayingUpdateCB(mediaItemTitle, mediaItemAlbumTitle, mediaItemArtist,
				mediaDuration,state);
	}
}
void NotifyDeviceNameCBExt(const char *name, int name_len) {

	if (g_callbacks) {
		g_callbacks->NotifyDeviceNameCB(name, name_len);
	}
}

/* *
 * @brief 退出的通知
 * */
void carplayExitCBExt() {
	if (g_callbacks) {
		g_callbacks->carplayExitCB();
	}
}

/* *
 * @brief 点击返回本地界面的按钮通知
 * */
void returnNativeUICBExt() {
	if (g_callbacks) {
		g_callbacks->returnNativeUICB();
	}
}

/* *
 * @brief carplay模式改变的通知
 * */
void modesChangeCBExt(DongleCarPlayModeState *modes) {
	CarPlayModeState *  m = (CarPlayModeState *)modes;
	if (g_callbacks) {
		g_callbacks->modesChangeCB(m);
	}
}

/* *
 * @brief carplay禁止蓝牙
 * */
void disableBluetoothCBExt() {
	if (g_callbacks) {
		g_callbacks->disableBluetoothCB();
	}
}

/* *
 * @brief 压低其他音频流音量
 * */
void caplayDuckAudioCBExt(double inDurationSecs, double inVolume) {
	if (g_callbacks) {
		g_callbacks->caplayDuckAudioCB(inDurationSecs, inVolume);
	}
}

/* *
 * @brief 还原其他音频流音量
 * */
void caplayUnduckAudioCBExt(double inDurationSecs) {
	if (g_callbacks) {
		g_callbacks->caplayUnduckAudioCB(inDurationSecs);
	}

}

/* *
 * @brief 音频流开始
 * @param 			handle 		该路音频流的操作句柄,要缓存起来,作为playStream/recordStream的第一个参数
 * @param			type  		音频流类型
 * @param 			rate		音频的采样率
 * @param 			bits		音频位宽
 * @param 			channels	音频通道数
 * */
void carplayAudioStartCBExt(int handle, DongleAudioStreamType type, int rate, int bits,
		int channels) {
	AudioStreamType t = (AudioStreamType)type;
	if (g_callbacks) {
		g_callbacks->carplayAudioStartCB(handle, t, rate, bits, channels);
	}
}

/* *
 * @brief 音频流停止
 * */
void carplayAudioStopCBExt(int handle, DongleAudioStreamType type) {
	AudioStreamType t = (AudioStreamType)type;
	if (g_callbacks) {
		g_callbacks->carplayAudioStopCB(handle, t);
	}
}

/* *
 * @brief 视频流开始
 * */
int carplayVideoStartCBExt() {
	if (g_callbacks) {
		return g_callbacks->carplayVideoStartCB();
	}
	return 0;
}

/* *
 * @brief 视频流停止
 * */
void carplayVideoStopCBExt() {
	if (g_callbacks) {
		g_callbacks->carplayVideoStopCB();
	}

}

/* *
 * @brief 视频流数据处理
 * */
int carplayVideoDataProcCBExt(const char *buf, int len) {
	if (g_callbacks) {
		return g_callbacks->carplayVideoDataProcCB(buf, len);
	}

	return 0;
}
//the above is config for CarPlay protocol stack

SdCarplay::SdCarplay(ICarplayCallbacks *pcbs) :
		mType(CARPLAY), mCarplayState(CarplayStateInit), mAirPlayModeState(
				nullptr), mCallbacks(pcbs) {
	g_callbacks = pcbs;
}

SdCarplay::~SdCarplay() {
	g_callbacks = nullptr;
}

void SdCarplay::setValue(const char *key, int value, bool save) {
	mapTypeInt[key] = value;
}

void SdCarplay::setValue(const char *key, const char *value, bool save) {
	mapTypeString[key] = value;
}

int SdCarplay::getIntValue(const char *key) {
	auto it = mapTypeInt.find(key);
	if (it != mapTypeInt.end()) {
		return it->second;
	}
	return 0;
}

const char *SdCarplay::getStringValue(const char *key) {
	auto it = mapTypeString.find(key);
	if (it != mapTypeString.end()) {
		return it->second.c_str();
	}
	return nullptr;
}

int SdCarplay::init() {
	CarPlayProtocolDelegateInit( &c2iDelegate );

	c2iDelegate.protocolIAP2LinkStatus_f	= iap2LinkStatusExt;
	c2iDelegate.protocolIAP2WriteData_f = iap2WriteDataExt;
	c2iDelegate.protocolCarPlaySessionStart_f = carplaySessionStartExt;
	c2iDelegate.protocolCarPlaySessionStop_f = carplaySessionStopExt;
	c2iDelegate.protocolSwitchUsbModeCB_f = switchUsbModeCBExt;
	c2iDelegate.protocolAppleTimeUpdateCB_f = appleTimeUpdateCBExt;
	c2iDelegate.protocolAppleLanguageUpdateCB_f = appleLanguageUpdateCBExt;
	c2iDelegate.protocolAppleCallStateUpdateCB_f = appleCallStateUpdateCBExt;
	c2iDelegate.protocolAppleNowPlayingUpdateCB = appleNowPlayingUpdateCBExt;
	c2iDelegate.protocolNotifyDeviceNameCB_f = NotifyDeviceNameCBExt;
	c2iDelegate.protocolCarPlayExitCB_f = carplayExitCBExt;
	c2iDelegate.protocolReturnNativeUICB_f = returnNativeUICBExt;
	c2iDelegate.protocolModesChangeCB_f = modesChangeCBExt;
	c2iDelegate.protocolDisableBluetoothCB_f = disableBluetoothCBExt;
	c2iDelegate.protocolCarPlayDuckAudioCB_f = caplayDuckAudioCBExt;
	c2iDelegate.protocolCarPlayUnduckAudioCB_f = caplayUnduckAudioCBExt;
	c2iDelegate.protocolCarPlayAudioStartCB_f = carplayAudioStartCBExt;
	c2iDelegate.protocolCarPlayAudioStopCB_f = carplayAudioStopCBExt;
	c2iDelegate.protocolCarPlayVideoStartCB_f = carplayVideoStartCBExt;
	c2iDelegate.protocolCarPlayVideoStopCB_f = carplayVideoStopCBExt;
	c2iDelegate.protocolCarPlayVideoDataProcCB_f = carplayVideoDataProcCBExt;

	CarPlayProtocolSetDelegate( &c2iDelegate );
	return 0;
}

static int _getBluetoothAddress( char * outAddress )
{
    FILE *  fd;
    char    buffer[64];
    char *  offset;
    char *  macAddress;

//    fd = fopen( "/data/bluetooth/deviceinfo.ini", "r" );
    //bt_addr=12:34:56:78:9A:BC
    fd = fopen( "/data/data/com.zjinnova.zlink/files/deviceinfo.ini", "r" );
    if( fd == NULL )
    {
//        CIpodLog::e( "open file deviceinfo.ini failed.\n");
        return -1;
    }
    while( fgets(buffer, 63, fd) != NULL )
    {
        offset = strstr( buffer, "bt_addr" );
        if( offset != NULL )
        {
            macAddress = strstr( offset, "=" );
            strcpy( outAddress, macAddress + 1 );
            outAddress[ 17 ] = '\0';
            fclose( fd );
            return 0;
        }
    }

	fclose( fd );
	return 0;
}


int SdCarplay::start(LinkType type, InitialMode initialmode) {
	char  tempStr[20] = {0};
	memset( tempStr, '\0', sizeof( tempStr ) );
	_getBluetoothAddress( tempStr );
	sendWiFiInformation(getStringValue("WIFI_SSID"),getStringValue("WIFI_PASSWD"));

	const char * oemIconPath = getStringValue("OEM_ICON_PATH");
	const char * userOemIconLabel = getStringValue("OEM_ICON_LABEL");

	char  oemIconLabel [ 128 ]= { 0 };
	if(userOemIconLabel != nullptr && strlen( userOemIconLabel ) > 0 )
	{
		strncpy(oemIconLabel,userOemIconLabel,128);
	}else{
		strcpy(oemIconLabel,"Car");
	}


	int handrive = getIntValue("RIGHTHAND_DRIVER");

	int width = getIntValue("SCREEN_WIDTH");
	int height = getIntValue("SCREEN_HEIGHT");

	int width_mm = getIntValue("SCREEN_WIDTH_MM");
	int height_mm = getIntValue("SCREEN_HEIGHT_MM");

	char widthStr[16];
	char heightStr[16];

	snprintf(widthStr, sizeof(widthStr), "%d", width);
	snprintf(heightStr, sizeof(heightStr), "%d", height);

	char widthMMStr[16];
	char heightMMStr[16];

	snprintf(widthMMStr, sizeof(widthMMStr), "%d", width_mm);
	snprintf(heightMMStr, sizeof(heightMMStr), "%d", height_mm);

	char mfi_auth_path[70] = {0};
	char mfi_auth_index[2] = {0};
	__system_property_get("persist.sys.mfi.index", mfi_auth_index);
//	if(strlen(mfi_auth_index) == 0)
//	{
//		__system_property_set("sys.mfi.auth.path", "/dev/i2c-0");
//	}else{
////		snprintf(mfi_auth_path, sizeof(mfi_auth_path), "/dev/i2c-%s", mfi_auth_index);
////		__system_property_set("sys.mfi.auth.path", mfi_auth_path);
//		__system_property_set("sys.mfi.auth.path", "/dev/i2c-0");
//	}

//	char* argv[] = {
//	    (char*)"carplay",
//
//	    (char*)"--no-knob",
//	    (char*)"--no-hi-fi-touch",
//	    (char*)"--no-lo-fi-touch",
//	    (char*)"--no-touchpad",
//	    (char*)"--no-proxsensor",
//
//	    (char*)"--btid", (char*)tempStr,
//
//	    (char*)"--width", (char*)"800",
//	    (char*)"--heigh", (char*)"480",
//	    (char*)"--widthMM", (char*)"150",
//	    (char*)"--heightMM", (char*)"90",
//
//	    // 这里借用ID填一个合法值 // borrowID type priority TakeConstraint BorrowConstraint
//	    (char*)"--modes", (char*)"screen=borrowID,take,niceToHave,anytime,anytime",
//	    (char*)"--modes", (char*)"mainAudio=borrowID,take,niceToHave,anytime,anytime",
//	    (char*)"--right-hand-drive", (char*)"true",
//	    (char*)"--enable-etc",
//
//	    (char*)"--primary-input-device", (char*)"2",
//	    (char*)"--enhanced-requestcarui",
//
//	    (char*)"--deviceid", (char*)"ABC123DEF456",
//	    (char*)"--iOSVersionMin", (char*)"13.0"
//	};
	char* argv[] = {
	    (char*)"carplay",
	    (char*)"--btid", (char*)tempStr,
	    (char*)"--width", widthStr,
	    (char*)"--heigh", heightStr,
	    (char*)"--widthMM", widthMMStr,
	    (char*)"--heightMM", heightMMStr,

	    // 这里借用ID填一个合法值 // borrowID type priority TakeConstraint BorrowConstraint
	    (char*)"--modes", (char*)"screen=borrowID,take,niceToHave,anytime,anytime",
	    (char*)"--modes", (char*)"mainAudio=borrowID,take,niceToHave,anytime,anytime",
	    (char*)"--right-hand-drive", handrive?(char*)"true":(char*)"false",

	    (char*)"--primary-input-device", (char*)"2",

	    (char*)"--deviceid", (char*)getStringValue("DEVID"),
	    (char*)"--icon-path", (char*)oemIconPath,
	    (char*)"--icon-label", (char*)oemIconLabel,
	    (char*)"--iOSVersionMin", (char*)"13.0"
	};

	int argc = sizeof(argv) / sizeof(argv[0]);
	startCarplay(argc, argv);
	return 0;
}

void SdCarplay::stop() {
	stopCarplay();
}

void SdCarplay::setCarplayAudioMode(bool release) {
	// 设置carplay音频模式
}

SdCarplay::CarplayState SdCarplay::getCarplayState(void) {
	// 获取carplay当前状态
	return mCarplayState;
}

void SdCarplay::sendSingleTouchscreen(unsigned short x, unsigned short y,
		bool pressed) {
	printf("sendSingleTouchscreen \n");
	sendTouchScreenUpdate(pressed,x,y);
}

void SdCarplay::sendMulPtrTouchscreen(unsigned char idx0, unsigned short x0,
		unsigned short y0, bool pressed0, unsigned char idx1, unsigned short x1,
		unsigned short y1, bool pressed1) {
	// 发送多点触摸
}

void SdCarplay::sendTelephoneButton(TelButton button, bool pressed) {
	// 发送电话按键
    int inButtonIndex =0 ;
    if (button == CallAccept && pressed == 1) {
    	inButtonIndex = 1;
    }
    else if (button == CallDrop && pressed ==1) {
    	inButtonIndex = 3;
    }
    else if (pressed == 0) {
    	inButtonIndex = 0;
    }
    sendCarPlayTelephonyUpdate(inButtonIndex);
}

void SdCarplay::sendMediaButton(MediaButton button, bool pressed) {
	// 发送媒体按键.
    uint16_t index = 0;
    if (pressed == 1)
    {
        switch (button)
        {
            case MediaNone:
                index = 0;
                break;
            case MediaPlay:
                index = 1;
                break;
            case MediaPause:
                index = 2;
                break;
            case MediaPlayPause:
            	if( gPlaybackStatus == 1 ){
            		 index = 2;
            	}else{
            		 index = 1;
            	}

                break;
            case MediaNext:
                index = 3;
                break;
            case MediaPrevious:
                index = 4;
                break;
        }
    }
    sendCarPlayMediaButton( index );
}

void SdCarplay::sendSiriButton(bool pressed) {
	// 发送Siri按键
	sendCarPlaySiriButton(pressed);
}

void SdCarplay::sendKnobUpdate(char selectButtonPressed, char homeButtonPressed,
		char backButtonPressed, double x, double y,
		char wheelPositionRelative) {
	// 发送knob信息
	sendKnobScreenUpdate(selectButtonPressed,homeButtonPressed,backButtonPressed,x,y,wheelPositionRelative);
}

void SdCarplay::forceKeyFrame(void) {
	// 强制关键帧
	sendCarPlayForceKeyFrame();
}

void SdCarplay::requestUI(AppleUIApp app) {
	// 请求UI
	if(app == AppleUIAppNomal)
	{
		sendCarPlayRequestUI();
	}else{
		const char * url = "nowplaying:";
		sendCarPlayRequestUIWithURL(url);
	}
}

void SdCarplay::setNightMode(bool enter) {
	// 设置夜间模式
	carplaySetNightMode(enter);
}

void SdCarplay::changeModes(CarplayTransferType inScreenType,
		CarplayTransferPriority inScreenPriority,
		CarplayConstraint inScreenTake, CarplayConstraint inScreenBorrow,
		CarplayTransferType inAudioType,
		CarplayTransferPriority inAudioPriority, CarplayConstraint inAudioTake,
		CarplayConstraint inAudioBorrow, CarplayTriState inPhone,
		CarplaySpeechMode inSpeech, CarplayTriState inTurnByTurn) {
	// 模式切换
	const char * inScreenBorrowID = "";
	const char * inAudioBorrowID = "";
	sendCarPlayChangeModeRequest(inScreenBorrowID,inScreenType,inScreenPriority,
			inScreenTake,inScreenBorrow,inAudioBorrowID,inAudioType,inAudioPriority,
			inAudioTake,inAudioBorrow,inPhone,inSpeech,inTurnByTurn);
}

void SdCarplay::playStream(int handle, void *buffer, int len, int frames,
		unsigned long long timestamp) {
	// 播放音频流
	carplayAudioStreamOutputProcessData(handle,buffer,len,frames,timestamp);
}

void SdCarplay::recordStream(int handle, void *buffer, int len, int frames,
		unsigned long long timestamp) {
	// 录制音频流
	carplayAudioStreamInputProc(handle,buffer,len,frames,timestamp);
}

void SdCarplay::setBtAddr(char mac[6]) {
	// 设置蓝牙地址
}

int SdCarplay::readIap2DataProc(char *buf, int len) {
	sendBluetoothRfcommData(len,buf);
	return 0;
}

void SdCarplay::setEncryptText(std::string &encryptText) {
	// 设置加密文本
}

std::string SdCarplay::rsaPubEncrypt(const std::string &clearText,
		const std::string &pubKey) {
	// 公钥加密
	return std::string("tinker");
}

void SdCarplay::setCarplayState(CarplayState state) {
	mCarplayState = state;
}



